#pragma once

template <typename IteratorType>
class IteratorRange {
public:
	IteratorRange(IteratorType begin, IteratorType end)
		: begin_(begin), end_(end) {}
	IteratorType begin() const { return begin_; }
	IteratorType end() const { return end_; }
private:
	const IteratorType begin_;
	const IteratorType end_;
};

template <typename IteratorType> IteratorRange<IteratorType>
MakeIteratorRange(IteratorType begin, IteratorType end) {
	return IteratorRange<IteratorType>(begin, end);
}

void LoadConfigByFormat(const char* fmt, char* ptr, TextUnpacker& unpacker);
template <typename T>
void LoadConfigByFormat(const char* fmt, T& obj, TextUnpacker& unpacker) {
	LoadConfigByFormat(fmt, (char*)&obj, unpacker);
}

template <typename T>
bool IsInRange(T v, T minVal, T maxVal) {
	return minVal <= v && v <= maxVal;
}

template <typename T, typename Unpacker>
T UnpackValue(Unpacker& unpacker) {
	T value;
	unpacker >> value;
	return value;
}

template <typename W, typename T>
size_t RandomByWeightValue(const T vals[], size_t num) {
	auto odds = System::Rand(W(0),
		std::accumulate(vals, vals + num, W(0)));
	for (size_t i = 0; i < num; ++i) {
		if ((odds -= vals[i]) < 0) {
			return i;
		}
	}
	return 0;
}

template <typename W, typename F, typename Iterator>
size_t RandomByWeightValue(Iterator itr, size_t num, const F& f) {
	std::vector<W> vals(num);
	for (size_t i = 0; i < num; ++i, ++itr) {
		vals[i] = f(*itr);
	}
	return RandomByWeightValue<W>(vals.data(), vals.size());
}

template <typename T>
T RandomVectorValue(const std::vector<T>& v) {
	switch (v.size()) {
	case 0: return T();
	case 1: return v[0];
	default: return v[System::Rand(0, (int)v.size())];
	}
}

template <typename RandomIt>
void RandomShuffle(RandomIt first, RandomIt last) {
	static std::mt19937 g(System::Randi(INT_MIN, INT_MAX, true));
	std::shuffle(first, last, g);
}

std::string StrPrintf(const char* fmt, ...);

bool IsKeyInString(const std::string_view& str,
	const std::string_view& key, char delimiter = ',');
bool IsKeyValueInRangeString(const std::string& str, int key);
